package userimage.texteditor;

import global.Utilities;
import userimage.page.Page;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.FileNotFoundException;
import java.util.ArrayList;

import static global.ProjectData.*;

public class TextEditor extends JPanel implements MouseListener, MouseMotionListener, ComponentListener, KeyEventDispatcher {

    Page fatherPage;

    String openFile;

    TextCore core;
    boolean movedinto = false;
    boolean choosing = false;

    public TextEditor(Page fatherPage, String file) throws FileNotFoundException {
        super();
        setLayout(null);
        setFile(file);
        core = new TextCore(this);
        this.fatherPage = fatherPage;
        enableInputMethods(true);

        addMouseListener(this);
        addMouseMotionListener(this);
        addComponentListener(this);
        DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
    }

    public void paint(Graphics __g) {
        Graphics2D g = (Graphics2D) __g;
        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setFont(theme.editorfont);

        boolean b = false;

        if (core.just_initialized) {
            core.paintBackground(g);
            b = true;
        }
        if (core.linenum_changed) {
            core.paintLineNum(g);
            core.linenum_changed = false;
        }
        if (core.choosingbg_changed) {
            try {
                core.paintChoosing(g);
                core.choosingbg_changed = false;
            } catch (IndexOutOfBoundsException ignored) {
            }
        }
        if (core.text_changed) {
            core.paintText(g);
            core.text_changed = false;
        }
        if (core.caret_blinged) {
            core.paintCaret(g);
            core.caret_blinged = false;
        }

        if (b) core.just_initialized = false;
    }

    public void setFile(String file) {
        openFile = file;
    }

    public String getOpenFile() {
        return openFile;
    }

    @Override
    public void mouseClicked(MouseEvent mouseEvent) {

    }

    @Override
    public void mousePressed(MouseEvent mouseEvent) {
        if (movedinto) {
            core.caret_bling.interrupt();
            core.editing = new ArrayList<>();
            core.start_choosing = new ArrayList<>();
            core.editing.add(core.caretToCoordination(core.toTextCoordination(mouseEvent.getX(), mouseEvent.getY())));
            core.start_choosing.add(core.editing.get(0));
            choosing = true;
            core.choosingbg_changed = true;
        }
    }

    @Override
    public void mouseReleased(MouseEvent mouseEvent) {
        choosing = false;
    }

    @Override
    public void mouseEntered(MouseEvent mouseEvent) {
        if (mouseEvent.getX() > core.getLinenumber_width()) {
            setCursor(new Cursor(Cursor.TEXT_CURSOR));
            movedinto = true;
        }
    }

    @Override
    public void mouseExited(MouseEvent mouseEvent) {
        if (mouseEvent.getX() > core.getLinenumber_width()) {
            setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
            movedinto = false;
        }
    }

    @Override
    public void mouseDragged(MouseEvent mouseEvent) {
        if (choosing) {
            core.caret_bling.interrupt();
            core.editing = new ArrayList<>();
            core.editing.add(core.caretToCoordination(core.toTextCoordination(mouseEvent.getX(), mouseEvent.getY())));
            core.choosingbg_changed = true;
        }
    }

    @Override
    public void mouseMoved(MouseEvent mouseEvent) {
        if (!movedinto) {
            if (mouseEvent.getX() > core.getLinenumber_width()) {
                setCursor(new Cursor(Cursor.TEXT_CURSOR));
                movedinto = true;
            }
        } else {
            if (mouseEvent.getX() < core.getLinenumber_width()) {
                setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                movedinto = false;
            }
        }
    }

    @Override
    public void componentResized(ComponentEvent componentEvent) {
        core.just_initialized = true;
        core.linenum_changed = true;
        core.text_changed = true;
        requestFocus();
    }

    @Override
    public void componentMoved(ComponentEvent componentEvent) {

    }

    @Override
    public void componentShown(ComponentEvent componentEvent) {

    }

    @Override
    public void componentHidden(ComponentEvent componentEvent) {

    }

    public void keyTyped(KeyEvent keyEvent) {
    }

    public void keyPressed(KeyEvent keyEvent) {
        switch (keyEvent.getKeyCode()) {
            case KeyEvent.VK_UP -> {
                core.doCaretUp(keyEvent);
                core.caret_bling.interrupt();
            }
            case KeyEvent.VK_DOWN -> {
                core.doCaretDown(keyEvent);
                core.caret_bling.interrupt();
            }
            case KeyEvent.VK_LEFT -> {
                if (!keyEvent.isControlDown())
                    core.doCaretLeft(keyEvent);
                else {
                    //noinspection StatementWithEmptyBody
                    while (core.doCaretLeft(keyEvent)) ;
                }
                core.caret_bling.interrupt();
            }
            case KeyEvent.VK_RIGHT -> {
                if (!keyEvent.isControlDown())
                    core.doCaretRight(keyEvent);
                else {
                    //noinspection StatementWithEmptyBody
                    while (core.doCaretRight(keyEvent)) ;
                }
                core.caret_bling.interrupt();
            }
            case KeyEvent.VK_BACK_SPACE -> {
                if (!keyEvent.isControlDown()) {
                    core.doBackspace(keyEvent);
                } else {
                    //noinspection StatementWithEmptyBody
                    while (core.doBackspace(keyEvent)) ;
                }
                core.caret_bling.interrupt();
            }
            case KeyEvent.VK_DELETE -> {
                if (!keyEvent.isControlDown()) {
                    core.doDelete(keyEvent);
                } else {
                    //noinspection StatementWithEmptyBody
                    while (core.doDelete(keyEvent)) ;
                }
                core.caret_bling.interrupt();
            }
            case KeyEvent.VK_ENTER -> {
                core.doEnter(keyEvent);
            }
        }
    }

    public void keyReleased(KeyEvent keyEvent) {

    }

    public boolean dispatchKeyEvent(KeyEvent keyEvent) {
        switch (keyEvent.getID()) {
            case KeyEvent.KEY_TYPED -> {
                keyTyped(keyEvent);
                keyPressed(keyEvent);
            }
            case KeyEvent.KEY_RELEASED -> keyReleased(keyEvent);
            case KeyEvent.KEY_PRESSED -> keyPressed(keyEvent);
        }
        return keyEvent.isConsumed();
    }
}
